

package com.hk.common.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;

/**
 * IP地址
 *
 * @author wujie
 */
@Component
public class ClientUtils {

    private static Logger log = LoggerFactory.getLogger(ClientUtils.class);

    /**
     * 本地ip
     */
    private static final String LOCAL_IP = "0:0:0:0:0:0:0:1";

    /**
     * 本地ip
     */
    private static final String LOCAL_IP_TWO = "127.0.0.1";

    /**
     * 获取IP地址
     * <p>
     * 使用Nginx等反向代理软件， 则不能通过request.getRemoteAddr()获取IP地址
     * 如果使用了多级反向代理的话，X-Forwarded-For的值并不止一个，而是一串IP地址，X-Forwarded-For中第一个非unknown的有效IP字符串，则为真实IP地址
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = null;
        try {
            ip = request.getHeader("x-forwarded-for");
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
        } catch (Exception e) {
            log.error("IPUtils ERROR ", e);
        }
        if(LOCAL_IP.equals(ip)||LOCAL_IP_TWO.equals(ip)){
            try {
                String realIp = getRealIP();
                ip = realIp==null?ip:realIp;
            } catch (Exception e) {
                log.error("无法获取服务IP");
            }
        }
        return ip;
    }


    public static boolean isReachable(String ipAddr) {
        boolean result = false;
        int time = 3000;
        try {
            result = InetAddress.getByName(ipAddr).isReachable(time);
        } catch (IOException e) {
            log.error("无法到达网络地址:"+ipAddr);
        }
        return result;
    }



    public static void main(String[] args) {
        try {
            String realIp = getRealIP();
            log.debug("getRealIP："+realIp);
            log.debug("isReachable:"+isReachable(realIp));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取本地真正的IP地址，即获得有线或者无线WiFi地址（真实物理网卡IP）。
     * 过滤虚拟机、蓝牙等地址
     */
    public static String getRealIP(){
        try {
            //获取到所有的网卡
            Enumeration<NetworkInterface> allNetInterfaces = NetworkInterface.getNetworkInterfaces();
            while (allNetInterfaces.hasMoreElements()) {
                NetworkInterface netInterface =  allNetInterfaces.nextElement();
                // 去除回环接口127.0.0.1，子接口，未运行的接口
                if (netInterface.isLoopback() || netInterface.isVirtual() || !netInterface.isUp()) {
                    continue;
                }
                //获取名称中是否包含 Intel Realtek 的网卡
                if (!netInterface.getDisplayName().contains("Intel")
                        && !netInterface.getDisplayName().contains("Realtek")
                        && !netInterface.getDisplayName().contains("Atheros")
                        && !netInterface.getDisplayName().contains("Broadcom")) {
                    continue;
                }
                Enumeration<InetAddress> addresses = netInterface.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress ip = addresses.nextElement();
                    if (ip != null) {
                        if (ip instanceof Inet4Address) {
                            return ip.getHostAddress();
                        }
                    }
                }
                break;
            }
        } catch (SocketException e) {
            log.error("e:",e);
        }
        return null;
    }

    /**
     *  获取本地真正的物理网卡地址地址，即获得有线或者无线WiFi地址（真实物理网卡IP）。
     *   过滤虚拟机、蓝牙等地址
     * @return 物理网卡MAC地址
     */
    public static String getLocalMac(){
        String macAddr = null;
        try {
            //获取到所有的网卡
            Enumeration<NetworkInterface> allNetInterfaces = NetworkInterface.getNetworkInterfaces();
            while (allNetInterfaces.hasMoreElements()) {
                NetworkInterface netInterface =  allNetInterfaces.nextElement();
                // 去除回环接口127.0.0.1，子接口，未运行的接口
                if (netInterface.isLoopback() || netInterface.isVirtual() || !netInterface.isUp()) {
                    continue;
                }
                //获取名称中是否包含 Intel Realtek 的网卡
                if (!netInterface.getDisplayName().contains("Intel")
                        && !netInterface.getDisplayName().contains("Realtek")
                        && !netInterface.getDisplayName().contains("Atheros")
                        && !netInterface.getDisplayName().contains("Broadcom")) {
                    continue;
                }

                StringBuilder sb = new StringBuilder();
                byte[] arr = netInterface.getHardwareAddress();
                for (int i=0;i< arr.length;i++) {
                    if(i!=0){
                        sb.append("-");
                    }
                    String temp = Integer.toHexString(arr[i]&0xff);
                    if(temp.length()==1){
                        sb.append("0");
                    }
                    sb.append(temp);
                }
                log.info(netInterface.getDisplayName()+"物理网卡地址:"+sb.toString());
                macAddr = sb.toString().toUpperCase();
                break;
            }
        } catch (SocketException e) {
            log.error("e:",e);
        }
        return macAddr;
    }

}
